<?

// Mates!
// Authors:
//   Ayush Agarwal <yush@umich.edu>
//   Adam Herscher <ahersche@umich.edu>
//   Jeff Powers <jrpowers@umich.edu>

require_once('config.php');
require_once('libmates.php');
require_once('nusoap.php');

// initialize soap, wsdl generation
$server = new soap_server;
$server->configureWSDL('mates', 'urn:mates');

// login_response data type
$server->wsdl->addComplexType(
  'login_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'session_id' => array('name' => 'session_id', 'type' => 'xsd:string')
  )
);

// guessloc_location data type
$server->wsdl->addComplexType(
  'guessloc_location',
  'complexType',
  'struct',
  'all',
  '',
  array('loc_id' => array('name' => 'loc_id', 'type' => 'xsd:int'),
        'name' => array('name' => 'name', 'type' => 'xsd:string'),
        'lat' => array('name' => 'lat', 'type' => 'xsd:float'),
        'long' => array('name' => 'long', 'type' => 'xsd:float'),
        'score' => array('name' => 'score', 'type' => 'xsd:float'),
        'source' => array('name' => 'source', 'type' => 'xsd:string')
  )
);

// guessloc_location_list data type
$server->wsdl->addComplexType(
  'guessloc_location_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:guessloc_location[]')
  ),
  'tns:guessloc_location'
);

// guessloc_response data type
$server->wsdl->addComplexType(
  'guessloc_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'locs' => array('name' => 'locs', 'type' => 'tns:guessloc_location_list')
  )
);

// getnearbylocs_location data type
$server->wsdl->addComplexType(
  'getnearbylocs_location',
  'complexType',
  'struct',
  'all',
  '',
  array('loc_id' => array('name' => 'loc_id', 'type' => 'xsd:int'),
        'name' => array('name' => 'name', 'type' => 'xsd:string'),
        'lat' => array('name' => 'lat', 'type' => 'xsd:float'),
        'long' => array('name' => 'long', 'type' => 'xsd:float'),
        'distance' =>array('name' => 'distance', 'type' => 'xsd:float'),
        'direction' =>array('name' => 'direction', 'type' => 'xsd:float')
  )
);

// getnearbylocs_location_list data type
$server->wsdl->addComplexType(
  'getnearbylocs_location_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:getnearbylocs_location[]')
  ),
  'tns:getnearbylocs_location'
);

// getnearbylocs_response data type
$server->wsdl->addComplexType(
  'getnearbylocs_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'locs' => array('name' => 'locs', 'type' => 'tns:getnearbylocs_location_list')
  )
);

// setloc_response data type
$server->wsdl->addComplexType(
  'setloc_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'loc_id' => array('name' => 'loc_id', 'type' => 'xsd:int')
  )
);

// interest_list data type
$server->wsdl->addComplexType(
  'interest_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'xsd:string[]')
  ),
  'xsd:string'
);

// getinterests_response data type
$server->wsdl->addComplexType(
  'getinterests_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'interests' => array('name' => 'interests', 'type' => 'tns:interest_list')
  )
);

// course_list data type
$server->wsdl->addComplexType(
  'course_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'xsd:string[]')
  ),
  'xsd:string'
);

// loc_q_item data type
$server->wsdl->addComplexType(
  'loc_q_item',
  'complexType',
  'struct',
  'all',
  '',
  array('msgtype' => array('name' => 'msgtype', 'type' => 'xsd:string'),
        'name' => array('name' => 'name', 'type' => 'xsd:string'),
        'loc_id' => array('name' => 'loc_id', 'type' => 'xsd:int'),
        'lat' => array('name' => 'lat', 'type' => 'xsd:float'),
        'long' => array('name' => 'long', 'type' => 'xsd:float'),
        'distance' => array('name' => 'distance', 'type' => 'xsd:float'),
        'direction' => array('name' => 'direction', 'type' => 'xsd:float'),
        'wall' => array('name' => 'wall', 'type' => 'xsd:string')
  )
);

// loc_q_list data type
$server->wsdl->addComplexType(
  'loc_q_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:loc_q_item[]')
  ),
  'tns:loc_q_item'
);

// msg_q_item data type
$server->wsdl->addComplexType(
  'msg_q_item',
  'complexType',
  'struct',
  'all',
  '',
  array('username' => array('name' => 'username', 'type' => 'xsd:string'),
        'msg' => array('name' => 'name', 'msg' => 'xsd:string'),
        'ts' => array('name' => 'ts', 'type' => 'xsd:string')
  )
);

// msg_q_list data type
$server->wsdl->addComplexType(
  'msg_q_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:msg_q_item[]')
  ),
  'tns:msg_q_item'
);

// rel_q_item data type
$server->wsdl->addComplexType(
  'rel_q_item',
  'complexType',
  'struct',
  'all',
  '',
  array('msgtype' => array('name' => 'msgtype', 'type' => 'xsd:string'),
        'name' => array('name' => 'name', 'type' => 'xsd:string'),
        'loc_id' => array('name' => 'loc_id', 'type' => 'xsd:int'),
        'reltype' => array('name' => 'reltype', 'type' => 'xsd:string'),
        'relparam' =>array('name' => 'relparam', 'type' => 'xsd:string')
  )
);

// rel_q_list data type
$server->wsdl->addComplexType(
  'rel_q_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:rel_q_item[]')
  ),
  'tns:rel_q_item'
);

// getcourses_response data type
$server->wsdl->addComplexType(
  'getcourses_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'courses' => array('name' => 'courses', 'type' => 'tns:course_list')
  )
);

// friend_list data type
$server->wsdl->addComplexType(
  'friend_list',
  'complexType',
  'array',
  '',
  'SOAP-ENC:Array',
  array(),
  array(
    array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'xsd:string[]')
  ),
  'xsd:string'
);

// getfriends_response data type
$server->wsdl->addComplexType(
  'getfriends_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'friends' => array('name' => 'friends', 'type' => 'tns:friend_list')
  )
);

// refresh_response data type
$server->wsdl->addComplexType(
  'refresh_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'loc_q' => array('name' => 'loc_q', 'type' => 'tns:loc_q_list'),
        'rel_q' => array('name' => 'rel_q', 'type' => 'tns:rel_q_list'),
        'msg_q' => array('name' => 'msg_q', 'type' => 'tns:msg_q_list')
  )
);

// getuserinfo_response data type
$server->wsdl->addComplexType(
  'getuserinfo_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string'),
        'msg' => array('name' => 'msg', 'type' => 'xsd:string'),
        'ts' => array('name' => 'ts', 'type' => 'xsd:string')
  )
);

// generic_response data type
$server->wsdl->addComplexType(
  'generic_response',
  'complexType',
  'struct',
  'all',
  '',
  array('success' => array('name' => 'success', 'type' => 'xsd:int'),
        'response' => array('name' => 'response', 'type' => 'xsd:string')
  )
);


// login service
$server->register('login',
  array('username' => 'xsd:string', 
        'password' => 'xsd:string'),
  array('return' => 'tns:login_response'),
  'urn:mates',
  'url:mates#login',
  'rpc',
  'encoded',
  'Authenticates the caller'
);

// logout service
$server->register('logout',
  array('session_id' => 'xsd:string'),
  array('return' => 'xsd:int'),
  'urn:mates',
  'url:mates#logout',
  'rpc',
  'encoded',
  'Log the caller out'
);

// register service
$server->register('register',
  array('username' => 'xsd:string',
        'password' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#register',
  'rpc',
  'encoded',
  'Register a new user'
);

// guessloc service
$server->register('guessloc',
  array('session_id' => 'xsd:string',
        'mac_addr' => 'xsd:string'),
  array('return' => 'tns:guessloc_response'),
  'urn:mates',
  'url:mates#guessloc',
  'rpc',
  'encoded',
  'Return a list of guessed locations based on ip'
);

// getnearbylocs service
$server->register('getnearbylocs',
  array('session_id' => 'xsd:string',
        'lat' => 'xsd:float',
        'long' => 'xsd:float'),
  array('return' => 'tns:getnearbylocs_response'),
  'urn:mates',
  'url:mates#getnearbylocs',
  'rpc',
  'encoded',
  'Return a list of nearby locations based on coordinates'
);

// setloc service
$server->register('setloc',
  array('session_id' => 'xsd:string',
        'name' => 'xsd:string',
        'lat' => 'xsd:float',
        'long' => 'xsd:float',
        'loc_id' => 'xsd:int',
        'mac_addr' => 'xsd:string'),
  array('return' => 'tns:setloc_response'),
  'urn:mates',
  'url:mates#setloc',
  'rpc',
  'encoded',
  'Set the user location'
);

// interest_add service
$server->register('interest_add',
  array('session_id' => 'xsd:string',
        'interest' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#interest_add',
  'rpc',
  'encoded',
  'Add an interest'
);

// interest_del service
$server->register('interest_del',
  array('session_id' => 'xsd:string',
        'interest' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#interest_del',
  'rpc',
  'encoded',
  'Delete an interest'
);

// getinterests service
$server->register('getinterests',
  array('session_id' => 'xsd:string'),
  array('return' => 'tns:getinterests_response'),
  'urn:mates',
  'url:mates#getinterests',
  'rpc',
  'encoded',
  'Return a list of interests'
);

// course_add service
$server->register('course_add',
  array('session_id' => 'xsd:string',
        'course' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#course_add',
  'rpc',
  'encoded',
  'Add a course'
);

// course_del service
$server->register('course_del',
  array('session_id' => 'xsd:string',
        'course' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#course_del',
  'rpc',
  'encoded',
  'Delete a course'
);

// getcourses service
$server->register('getcourses',
  array('session_id' => 'xsd:string'),
  array('return' => 'tns:getcourses_response'),
  'urn:mates',
  'url:mates#getcourses',
  'rpc',
  'encoded',
  'Return a list of courses'
);

// friend_add service
$server->register('friend_add',
  array('session_id' => 'xsd:string',
        'friend_username' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#friend_add',
  'rpc',
  'encoded',
  'Add a friend'
);

// friend_del service
$server->register('friend_del',
  array('session_id' => 'xsd:string',
        'friend_username' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#friend_del',
  'rpc',
  'encoded',
  'Delete a friend'
);

// getfriends service
$server->register('getfriends',
  array('session_id' => 'xsd:string'),
  array('return' => 'tns:getfriends_response'),
  'urn:mates',
  'url:mates#getfriends',
  'rpc',
  'encoded',
  'Return a list of friends'
);

// refresh service
$server->register('refresh',
  array('session_id' => 'xsd:string'),
  array('return' => 'tns:refresh_response'),
  'urn:mates',
  'url:mates#refresh',
  'rpc',
  'encoded',
  'Ping server for updates'
);

// sendmsg service
$server->register('sendmsg',
  array('session_id' => 'xsd:string',
        'username' => 'xsd:string',
        'msg' => 'xsd_string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#sendmsg',
  'rpc',
  'encoded',
  'Send a message to another user'
);

// setwall service
$server->register('setwall',
  array('session_id' => 'xsd:string',
        'msg' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#setwall',
  'rpc',
  'encoded',
  'Set the wall for the current location'
);

// getuserinfo service
$server->register('getuserinfo',
  array('session_id' => 'xsd:string',
        'username' => 'xsd:string'),
  array('return' => 'tns:getuserinfo_response'),
  'urn:mates',
  'url:mates#getuserinfo',
  'rpc',
  'encoded',
  'Get userinfo for the specified user'
);

// setuserinfo service
$server->register('setuserinfo',
  array('session_id' => 'xsd:string',
        'msg' => 'xsd:string'),
  array('return' => 'tns:generic_response'),
  'urn:mates',
  'url:mates#setuserinfo',
  'rpc',
  'encoded',
  'Set userinfo of the caller'
);


// login function
function login($username, $password) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'session_id' => '');

  if (!valid_username($username)) // validate username
    return array('success' => '0',
                 'response' => $GLOBALS['err_username'],
                 'session_id' => '');
  if (!valid_password($password)) // validate password
    return array('success' => '0',
                 'response' => $GLOBALS['err_password'],
                 'session_id' => '');

  // authenticate
  $query = "select user_id, session_id from users where username = '$username' and password = '$password'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'session_id' => '');
  if (!mysql_num_rows($res)) // authentication failed
    return array('success' => '0',
                 'response' => 'Invalid username and/or password.',
                 'session_id' => '');
  
  $row = mysql_fetch_object($res);
  $user_id = $row->user_id;
  $session_id = $row->session_id;

  // generate and store session_id
  for ($i = 0; $i < 10; $i++) // 10 chars
    $new_session_id .= chr(round(rand(65, 90))); // values A-Z
  
  $query = "select loc_id from in_loc where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'session_id' => '');
  $row = mysql_fetch_object($res);
  if ($row)
    exit_loc($user_id, $row->loc_id, $session_id, $username, 1);
  
  $query = "update users set session_id = '$new_session_id', lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'session_id' => '');

  if ($session_id != "") // user is already logged in, terminate previous session, success!
    return array('success' => '1',
                 'response' => 'Previous session terminated.',
                 'session_id' => $new_session_id);
  else // success!
    return array('success' => '1',
                 'response' => '',
                 'session_id' => $new_session_id);
}

// logout function
function logout($session_id) {
  init_func();
  if (!db_connect()) // connect to the database
    return 0;
  
  if (!valid_session_id($session_id)) // validate session_id
    return 0;

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return 0;

  // delete session_id
  $res = mysql_query("update users set session_id = '', lastreq_ts = NOW() where user_id = '$user_id'");
  if (!$res)
    return 0;

  // we don't use getloc() here, because it's okay if user is not in a location
  $query = "select loc_id from in_loc where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return 0;

  if (mysql_num_rows($res)) { // user has set a location
    $row = mysql_fetch_object($res);
    $loc_id = $row->loc_id;
    
    list($p1, $p2) = exit_loc($user_id, $loc_id, $session_id, $username, 1);
    if (!$p1)
      return 0;

  }
    
  return 1;
}

// register function
function register($username, $password) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');

  if (!valid_username($username)) // validate username
    return array('success' => '0',
                 'response' => $GLOBALS['err_username'],
                 'session_id' => '');
  if (!valid_password($password)) // validate password
    return array('success' => '0',
                 'response' => $GLOBALS['err_password'],
                 'session_id' => '');

  // check if username is taken
  $query = "select user_id from users where username = '$username'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  if (mysql_num_rows($res)) // username is taken
    return array('success' => '0',
                 'response' => 'Username is already in use.');

  $query = "insert into users (user_id, username, password, session_id, lastreq_ts) values (NULL, '$username', '$password', '', '1000-01-01 00:00:00')";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  return array('success' => '1',
               'response' => '');
}

// guessloc function
// mac_addr is ignored if it is set to 00:00:00:00:00:00
function guessloc($session_id, $mac_addr) {
  init_func();
  $locs = array();

  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'locs' => $locs);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'locs' => $locs);

  if (!ereg("^[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}$", $mac_addr)) // validate mac_addr
    return array('success' => '0',
                 'response' => 'Invalid mac address.',
                 'locs' => $locs);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2,
                 'locs' => $locs);

  $ip = getenv("REMOTE_ADDR");
  
  $locnames = array(); // We use this as an index in order to easily search the multidimensional array

  // IPs seen by any user
  $query = "select locs.loc_id, name, lat, locs.long, sum(count)*{$GLOBALS['GUESSLOC_IP_WEIGHT']} as score, 'ip' as source from ips, locs where ips.loc_id = locs.loc_id and ip = '$ip' group by ips.loc_id";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'locs' => $locs);
  while ($row = mysql_fetch_assoc($res)) {
    array_push($locs, $row);
    array_push($locnames, $row["name"]);
  }

  // IPs seen by this user
  $query = "select name, sum(count)*{$GLOBALS['GUESSLOC_USER_IP_WEIGHT']} as score from ips, locs where ips.loc_id = locs.loc_id and ip = '$ip' and user_id = '$user_id' group by ips.loc_id";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'locs' => $locs);
  while ($row = mysql_fetch_assoc($res)) {
    $key = array_search($row["name"], $locnames);
    if ($key === FALSE) // this should never happen
      return array('success' => '0',
                   'response' => 'Seek error: Unable to find expected result.',
                   'locs' => $locs);
    $locs[$key]['score'] += $row["score"];
  }

  if ($mac_addr != "00:00:00:00:00:00") {
    // Access point mac addresses seen by any user
    $query = "select locs.loc_id, name, lat, locs.long, sum(count)*{$GLOBALS['GUESSLOC_MAC_WEIGHT']} as score, 'mac' as source from mac_addrs, locs where mac_addrs.loc_id = locs.loc_id and mac_addr = '$mac_addr' and user_id = '$user_id' group by mac_addrs.loc_id";
    $res = mysql_query($query);
    if (!$res)
      return array('success' => '0',
                   'response' => db_err($query),
                   'locs' => $locs);
    while ($row = mysql_fetch_assoc($res)) {
      $key = array_search($row["name"], $locnames);
      if ($key === FALSE) {
        array_push($locs, $row);
        array_push($locnames, $row["name"]);
      } else {
        $locs[$key]['score'] += $row["score"];
        $locs[$key]['source'] = "ip,mac";
      }
    }
    // Access point mac addresses seen by this user
    $query = "select name, sum(count)*{$GLOBALS['GUESSLOC_USER_MAC_WEIGHT']} as score from mac_addrs, locs where mac_addrs.loc_id = locs.loc_id and mac_addr = '$mac_addr' group by mac_addrs.loc_id";
    $res = mysql_query($query);
    if (!$res)
      return array('success' => '0',
                   'response' => db_err($query),
                   'locs' => $locs);
    while ($row = mysql_fetch_assoc($res)) {
      $key = array_search($row["name"], $locnames);
      if ($key === FALSE) // this should never happen
        return array('success' => '0',
                     'response' => 'Seek error: Unable to find expected result.',
                     'locs' => $locs);
      $locs[$key]['score'] += $row["score"];
    }
  }

  // Adjust scores to be relative
  $total_score = 0;
  foreach ($locs as $loc)
    $total_score += $loc['score'];
  $locs_size = count($locs);
  for ($i = 0; $i < $locs_size; $i++)
    $locs[$i]["score"] = $locs[$i]["score"] / $total_score;

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'locs' => $locs);

  return array('success' => '1',
               'response' => '',
               'locs' => $locs);
}

// getnearbylocs function
function getnearbylocs($session_id, $lat, $long) {
  init_func();
  $locs = array();

  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'locs' => $locs);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'locs' => $locs);
  
  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2,
                 'locs' => $locs);

  if (!is_float($lat)) // validate lat
    return array('success' => '0',
                 'response' => 'Invalid lat.');
  if (!is_float($long)) // validate long
    return array('success' => '0',
                 'response' => 'Invalid long.');

  $query = "select loc_id, name, lat, locs.long, 0 as distance, 0 as direction from locs";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'locs' => $locs);

  $lat1 = $lat*pi()/180; // convert to radians
  $long1 = $long*pi()/180;
  
  while ($row = mysql_fetch_assoc($res)) {
    $complat = $row["lat"] * pi() / 180;
    $complong = $row["long"] * pi() / 180;
  
    // See http://williams.best.vwh.net/avform.htm if you wish to disect the formula.
    $distance = 2 * asin(sqrt(pow(sin(($lat1-$complat)/2), 2) + cos($lat1) * cos($complat) * pow(sin(($long1-$complong)/2), 2))); // distance in radians, used for direction calculations

    $distanceft = $distance * 180 * 60 / pi() * 1.15078 * 5280;

    # should really also account for poles above: http://williams.best.vwh.net/avform.htm#Crs
    
    if ($distance > 0) {
      if (sin($complong-$long1) > 0 ) // must be > for Neg Western Hemisphere Longitude values
        $direction = acos((sin($complat)-sin($lat1)*cos($distance))/(sin($distance)*cos($lat1)));
      else
        $direction = 2*pi()-acos((sin($complat)-sin($lat1)*cos($distance))/(sin($distance)*cos($lat1)));
      $directiondeg = $direction  * 180 / pi();
    } else
      $directiondeg = 0; // if distance is 0 (coords are the same), the above formula would result in a divide by zero

    if ($distanceft < $GLOBALS['NEARBY_LOC_DIST_LIMIT_FT']) {
      $row['distance'] = $distanceft;
      $row['direction'] = $directiondeg;
      array_push($locs, $row);
    }
  }

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'locs' => $locs);

  return array('success' => '1',
               'response' => '',
               'locs' => $locs);
}

// setloc function
// loc_id parameter is optional and only used if name is not set, 
// in which case name, lat, and long are ignored.
// mac_addr is ignored if it is set to 00:00:00:00:00:00
function setloc($session_id, $name, $lat, $long, $loc_id, $mac_addr) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'loc_id' => 0);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'loc_id' => 0);
  if (!empty($name)) {
    $loc_id = 0;
    if (!valid_location_name($name)) // validate location name
      return array('success' => '0',
                   'response' => $GLOBALS['err_locname'],
                   'loc_id' => $loc_id);
    if (!is_float($lat)) // validate lat
      return array('success' => '0',
                   'response' => 'Invalid lat.',
                   'loc_id' => $loc_id);
    if (!is_float($long)) // validate long
      return array('success' => '0',
                   'response' => 'Invalid long.',
                    'loc_id' => $loc_id);
  } else {
    if (!is_int($loc_id)) // validate loc_id
      return array('success' => '0',
                   'response' => 'Invalid loc_id.',
                    'loc_id' => 0);
    $query = "select loc_id from locs where loc_id = '$loc_id'";
    $res = mysql_query($query);
    if (!$res)
      return array('success' => '0',
                   'response' => db_err($query),
                   'loc_id' => 0);
  
    if (!mysql_num_rows($res)) // unknown loc_id
      return array('success' => '0',
                   'response' => 'Unknown loc_id.',
                    'loc_id' => 0);
  }

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2,
                 'loc_id' => $loc_id);
  
  $ip = getenv("REMOTE_ADDR");

  // if the user is already in a location, take him/her out
  // we don't use getloc() here, because it's okay if user is not in a location
  $query = "select loc_id from in_loc where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_id' => $loc_id);
  
  if (mysql_num_rows($res)) { // user has set a location
    $row = mysql_fetch_object($res);
    $loc_id_old = $row->loc_id;

    list($p1, $p2) = exit_loc($user_id, $loc_id_old, $session_id, $username, 0);
    if (!$p1)
      return array('success' => '0',
                   'response' => $p2,
                   'loc_id' => $loc_id);
    $first_setloc_this_session = false;
  } else
    $first_setloc_this_session = true;
  
  // add location to locs table if necessary, get loc_id
  if (!empty($name)) {
    $query = "select loc_id from locs where name = '$name' and abs(lat - '$lat') < .0001 and abs(locs.long - '$long') < .0001";
    $res = mysql_query($query);
    if (!$res)
      return array('success' => '0',
                   'response' => db_err($query),
                   'loc_id' => $loc_id);
    if (!mysql_num_rows($res)) { // location does not exist
      $query2 = "insert into locs (loc_id, name, lat, locs.long) values (NULL, '$name', '$lat', '$long')";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
      $loc_id = mysql_insert_id();
    
      // populate loc_rel with new location info (bidirerctional) + add to users loc_queues if they're in those locations
      $query2 = "select loc_id, lat, locs.long, name from locs where loc_id <> '$loc_id'";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);

      $lat1 = $lat*pi()/180; // convert to radians
      $long1 = $long*pi()/180;

      while ($row2 = mysql_fetch_assoc($res2)) {
        $complat = $row2["lat"] * pi() / 180;
        $complong = $row2["long"] * pi() / 180;
  
        // See http://williams.best.vwh.net/avform.htm if you wish to disect the formula.
        $distance = 2 * asin(sqrt(pow(sin(($lat1-$complat)/2), 2) + cos($lat1) * cos($complat) * pow(sin(($long1-$complong)/2), 2))); // distance in radians, used for direction calculations

        $distanceft = $distance * 180 * 60 / pi() * 1.15078 * 5280;

        # should really also account for poles above: http://williams.best.vwh.net/avform.htm#Crs
    
        if ($distance > 0) {
          if (sin($complong-$long1) > 0 ) // must be > for Neg Western Hemisphere Longitude values
            $direction = acos((sin($complat)-sin($lat1)*cos($distance))/(sin($distance)*cos($lat1)));
          else
            $direction = 2*pi()-acos((sin($complat)-sin($lat1)*cos($distance))/(sin($distance)*cos($lat1)));
          $directiondeg = $direction  * 180 / pi();
        } else
          $directiondeg = 0; // if distance is 0 (coords are the same), the above formula would result in a divide by zero

        $directiondeg_inverse = ($directiondeg + 180) % 360;
      
        if ($distanceft < $GLOBALS['NEARBY_REL_LOC_DIST_LIMIT_FT']) {
          // populate loc_rel
          $query3 = "insert into loc_rel (loc_id, neighbor_id, distance, direction) values ('$loc_id', '{$row2['loc_id']}', '$distanceft', '$directiondeg')";
          $res3 = mysql_query($query3);
          if (!$res3)
            return array('success' => '0',
                         'response' => db_err($query3),
                         'loc_id' => $loc_id);
          $query3 = "insert into loc_rel (loc_id, neighbor_id, distance, direction) values ('{$row2['loc_id']}', '$loc_id', '$distanceft', '$directiondeg_inverse')";
          $res3 = mysql_query($query3);
          if (!$res3)
            return array('success' => '0',
                         'response' => db_err($query3),
                         'loc_id' => $loc_id);
          // populate queues
          $query3 = "insert into loc_queue (session_id, name, loc_id, msg_type, lat, loc_queue.long, distance, direction, wall, ts) 
                     select session_id, '$name', '$loc_id', 'loc_add', '$lat', '$long', '$distanceft', '$directiondeg_inverse', walls.message, NOW()
                     from users, in_loc
                     left join walls on in_loc.loc_id=walls.loc_id
                     where users.user_id = in_loc.user_id and 
                     in_loc.loc_id = '{$row2['loc_id']}'";
          $res3 = mysql_query($query3);
          if (!$res3)
            return array('success' => '0',
                         'response' => db_err($query3),
                         'loc_id' => $loc_id);
        }
      }
    } else { // location exists
      // we don't allow multiple locations with the same name, lat, and long,
      // so we drop the user into the existing location with that information.
      $row = mysql_fetch_object($res);
      $loc_id = $row->loc_id;
    }
  }
  
  // add info to ips table if necessary or increment existing count
  $query = "select count from ips where ip = '$ip' and user_id = '$user_id' and loc_id = '$loc_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_id' => $loc_id);
  if (!mysql_num_rows($res)) { // info does not exist
    $query2 = "insert into ips (ip, user_id, loc_id, count, lastused_ts) values ('$ip', '$user_id', '$loc_id', '1', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query2),
                   'loc_id' => $loc_id);
  } else { // info exists
    $row = mysql_fetch_object($res);
    $count = $row->count + 1;
    $query2 = "update ips set count = '$count', lastused_ts = NOW() where ip = '$ip' and user_id = '$user_id' and loc_id = '$loc_id'";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query2),
                   'loc_id' => $loc_id);
  }

  // add info to mac_addrs table if necessary or increment existing count
  if ($mac_addr != '00:00:00:00:00:00') {
    $query = "select count from mac_addrs where mac_addr = '$mac_addr' and user_id = '$user_id' and loc_id = '$loc_id'";
    $res = mysql_query($query);
    if (!$res)
      return array('success' => '0',
                   'response' => db_err($query),
                   'loc_id' => $loc_id);
    if (!mysql_num_rows($res)) { // info does not exist
      $query2 = "insert into mac_addrs (mac_addr, user_id, loc_id, count, lastused_ts) values ('$mac_addr', '$user_id', '$loc_id', '1', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
    } else { // info exists
      $row = mysql_fetch_object($res);
      $count = $row->count + 1;
      $query2 = "update mac_addrs set count = '$count', lastused_ts = NOW() where mac_addr = '$mac_addr' and user_id = '$user_id' and loc_id = '$loc_id'";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
    }
  }
  
  // update user's location (can't use getloc here due to cases)
  $query = "replace into in_loc (user_id, loc_id) values ('$user_id', '$loc_id')";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_id' => $loc_id);
  
  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_id' => $loc_id);

  // generate list of nearby locations
  $query = "insert into loc_queue (session_id, name, loc_id, msg_type, lat, loc_queue.long, distance, direction, wall, ts) 
            select '$session_id', locs.name, loc_rel.neighbor_id, 'loc_add', locs.lat, locs.long, loc_rel.distance, loc_rel.direction, walls.message, NOW()
            from loc_rel, locs
            left join walls on locs.loc_id=walls.loc_id
            where locs.loc_id = loc_rel.neighbor_id and 
            loc_rel.loc_id = '$loc_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_id' => $loc_id);

  // generate relationships
  // this looks bad, but inner queries should be cached by mysql.
  // but, we should really rewrite some of these to use more joins than nested queries!
  $query = "
select u.session_id, u.username, in1.loc_id, 'location' as rel_type, '' as rel_param
from users u, in_loc in1
where in1.loc_id = '$loc_id' and 
      in1.user_id <> '$user_id' and
      in1.user_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id, 'location' as rel_type, '' as rel_param
from users u, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      in1.loc_id = lr.neighbor_id and
      in1.user_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id, 'friend' as rel_type, '' as rel_param
from users u, friends f, in_loc in1
where in1.loc_id = '$loc_id' and
      f.user_id = '$user_id' and
      f.friend_id = in1.user_id and
      f.friend_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id, 'friend' as rel_type, '' as rel_param
from users u, friends f, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      f.user_id = '$user_id' and
      f.friend_id = in1.user_id and
      f.friend_id = u.user_id and
      in1.loc_id = lr.neighbor_id

union all
select u.session_id, u.username, in1.loc_id, 'friendrev1' as rel_type, '' as rel_param
from users u, friends f, in_loc in1
where in1.loc_id = '$loc_id' and
      f.friend_id = '$user_id' and
      f.user_id = in1.user_id and
      f.user_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id, 'friendrev1' as rel_type, '' as rel_param
from users u, friends f, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      f.friend_id = '$user_id' and
      f.user_id = in1.user_id and
      f.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id

union all
select u.session_id, u.username, in1.loc_id, 'fof' as rel_type, u2.username as rel_param
from users u, users u2, friends f, friends f2, in_loc in1
where in1.loc_id = '$loc_id' and
      f.user_id = '$user_id' and
      f.friend_id = f2.user_id and
      f2.friend_id = in1.user_id and
      f2.friend_id = u.user_id and
      f2.user_id = u2.user_id

union all
select u.session_id, u.username, in1.loc_id, 'fof' as rel_type, u2.username as rel_param
from users u, users u2, friends f, friends f2, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      f.user_id = '$user_id' and
      f.friend_id = f2.user_id and
      f2.friend_id = in1.user_id and
      f2.friend_id = u.user_id and
      in1.loc_id = lr.neighbor_id and
      f2.user_id = u2.user_id

union all
select u.session_id, u.username, in1.loc_id, 'interest' as rel_type, i2.interest as rel_param
from users u, interests i1, interests i2, in_loc in1
where in1.loc_id = '$loc_id' and
      i1.user_id = '$user_id' and
      i1.interest = i2.interest and
      i2.user_id <> '$user_id' and
      i2.user_id = in1.user_id and
      i2.user_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id, 'interest' as rel_type, i2.interest as rel_param
from users u, interests i1, interests i2, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      i1.user_id = '$user_id' and
      i1.interest = i2.interest and
      i2.user_id <> '$user_id' and
      i2.user_id = in1.user_id and
      i2.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id

union all
select u.session_id, u.username, in1.loc_id, 'course' as rel_type, c2.course as rel_param
from users u, courses c1, courses c2, in_loc in1
where in1.loc_id = '$loc_id' and
      c1.user_id = '$user_id' and
      c1.course = c2.course and
      c2.user_id <> '$user_id' and
      c2.user_id = in1.user_id and
      c2.user_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id, 'course' as rel_type, c2.course as rel_param
from users u, courses c1, courses c2, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      c1.user_id = '$user_id' and
      c1.course = c2.course and
      c2.user_id <> '$user_id' and
      c2.user_id = in1.user_id and
      c2.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id
  ";

if ($first_setloc_this_session) // for online friend notification
  $query .= "

union all
select session_id, username, '$loc_id' as loc_id, 'friendrev2' as rel_type, '' as rel_param
from users, friends
where friends.friend_id = '$user_id' and 
      friends.user_id = users.user_id

union all
select session_id, username, in_loc.loc_id, 'user_on' as rel_type, locs.name as rel_param
from users, friends, in_loc, locs
where friends.user_id = '$user_id' and 
      friends.friend_id = users.user_id and 
      friends.friend_id = in_loc.user_id and 
      in_loc.loc_id = locs.loc_id
";
  
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_id' => $loc_id);
  while ($row = mysql_fetch_assoc($res)) {
    switch($row["rel_type"]) {
    case "friendrev1":
      // add to target's rel_queue only (for one-way friend relationships - notify target when his friend signs on nearby)
      $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('{$row["session_id"]}', '$username', '$loc_id', 'rel_add', 'friend', '', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
      break;
    case "friendrev2":
      // add to target's rel_queue only (for one-way friend relationships - notify target when his friend signs on at all -- nearby or not)
      $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('{$row["session_id"]}', '$username', '$loc_id', 'user_on', 'friend', '', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
      break;
    case "friend":
      // add to user's rel_queue only (for one-way friend relationships - notify user of his nearby friends)
      $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('$session_id', '{$row["username"]}', '{$row["loc_id"]}', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
      break;
    case "user_on":
      // add to user's rel_queue only (for one-way friend relationsihps - notify user of his online friends, nearby or not)
      $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('$session_id', '{$row["username"]}', '{$row["loc_id"]}', 'user_on', 'friend', '{$row["rel_param"]}', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
      break;
    default:
      // add to user's rel_queue
      $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('$session_id', '{$row["username"]}', '{$row["loc_id"]}', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
      // add to target's rel_queue
      $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('{$row["session_id"]}', '$username', '$loc_id', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
      $res2 = mysql_query($query2);
      if (!$res2)
        return array('success' => '0',
                     'response' => db_err($query2),
                     'loc_id' => $loc_id);
    }
  }

  return array('success' => '1',
               'response' => '',
               'loc_id' => $loc_id);
}

// interest_add function
function interest_add($session_id, $interest) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_generic($interest)) // validate interest
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);
  
  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);

  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);

  $query = "insert into interests (user_id, interest) values ('$user_id', '$interest')";
  $res = mysql_query($query);
  if (!$res) {
    if (mysql_errno() == 1062)
      return array('success' => '0',
                   'response' => 'The interest already exists.');
    return array('success' => '0',
                 'response' => db_err($query));
  }

  // update rel_queue
  $query = "
select u.session_id, u.username, in1.loc_id, 'interest' as rel_type, '$interest' as rel_param
from users u, interests i1, in_loc in1
where in1.loc_id = '$loc_id' and
      i1.interest = '$interest' and
      i1.user_id <> '$user_id' and
      i1.user_id = u.user_id and
      i1.user_id = in1.user_id

union all
select u.session_id, u.username, in1.loc_id, 'interest' as rel_type, '$interest' as rel_param
from users u, interests i1, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      i1.interest = '$interest' and
      i1.user_id <> '$user_id' and
      i1.user_id = in1.user_id and
      i1.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id
  ";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  while ($row = mysql_fetch_assoc($res)) {
    // add to user's rel_queue
    $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('$session_id', '{$row["username"]}', '{$row["loc_id"]}', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query2));

    // add to target's rel_queue
    $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('{$row["session_id"]}', '$username', '$loc_id', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query2));
  }
  
  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
    
  return array('success' => '1',
               'response' => '');
}

// interest_del function
function interest_del($session_id, $interest) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_generic($interest)) // validate interest
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);

  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);
  
  $query = "delete from interests where user_id = '$user_id' and interest = '$interest'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  // update target's rel_queue only
  $query = "
insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts)

select session_id, '$username' as username, '$loc_id' as loc_id, 'rel_del' as msg_type, 'interest' as rel_type, '$interest' as rel_param, NOW()
from users u, interests i1, in_loc in1
where in1.loc_id = '$loc_id' and
      i1.interest = '$interest' and
      i1.user_id <> '$user_id' and
      i1.user_id = u.user_id and
      i1.user_id = in1.user_id

union all
select session_id, '$username' as username, '$loc_id' as loc_id, 'rel_del' as msg_type, 'interest' as rel_type, '$interest' as rel_param, NOW()
from users u, interests i1, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      i1.interest = '$interest' and
      i1.user_id <> '$user_id' and
      i1.user_id = in1.user_id and
      i1.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id
  ";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  
  return array('success' => '1',
               'response' => '');
}

// getinterests function
function getinterests($session_id) {
  init_func();
  $interests = array();

  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'interests' => $interests);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'interests' => $interests);
  
  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2,
                 'interests' => $interests);
    
  $query = "select interest from interests where user_id = '$user_id' order by interest";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'interests' => $interests);
  
  while ($row = mysql_fetch_object($res))
    array_push($interests, $row->interest);

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'interests' => $interests);

  return array('success' => '1',
               'response' => '',
               'interests' => $interests);
}

// course_add function
function course_add($session_id, $course) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_generic($course)) // validate course
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);

  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);

  $query = "insert into courses (user_id, course) values ('$user_id', '$course')";
  $res = mysql_query($query);
  if (!$res) {
    if (mysql_errno() == 1062)
      return array('success' => '0',
                   'response' => 'The course already exists.');
    return array('success' => '0',
                 'response' => db_err($query));
  }

  // update rel_queue
  $query = "
select u.session_id, u.username, in1.loc_id, 'course' as rel_type, '$course' as rel_param
from users u, courses c1, in_loc in1
where in1.loc_id = '$loc_id' and
      c1.course = '$course' and
      c1.user_id <> '$user_id' and
      c1.user_id = u.user_id and
      c1.user_id = in1.user_id

union all
select u.session_id, u.username, in1.loc_id, 'course' as rel_type, '$course' as rel_param
from users u, courses c1, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      c1.course = '$course' and
      c1.user_id <> '$user_id' and
      c1.user_id = in1.user_id and
      c1.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id
  ";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  while ($row = mysql_fetch_assoc($res)) {
    // add to user's rel_queue
    $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('$session_id', '{$row["username"]}', '{$row["loc_id"]}', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query2));
    
    // add to target's rel_queue
    $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('{$row["session_id"]}', '$username', '$loc_id', 'rel_add', '{$row["rel_type"]}', '{$row["rel_param"]}', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query2));
  }
  
  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  return array('success' => '1',
               'response' => '');
}

// course_del function
function course_del($session_id, $course) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_generic($course)) // validate course
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);

  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);
  
  $query = "delete from courses where user_id = '$user_id' and course = '$course'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  // update target's rel_queue only
  $query = "
insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts)

select session_id, '$username' as username, '$loc_id' as loc_id, 'rel_del' as msg_type, 'course' as rel_type, '$course' as rel_param, NOW()
from users u, courses c1, in_loc in1
where in1.loc_id = '$loc_id' and
      c1.course = '$course' and
      c1.user_id <> '$user_id' and
      c1.user_id = u.user_id and
      c1.user_id = in1.user_id

union all
select session_id, '$username' as username, '$loc_id' as loc_id, 'rel_del' as msg_type, 'course' as rel_type, '$course' as rel_param, NOW()
from users u, courses c1, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      c1.course = '$course' and
      c1.user_id <> '$user_id' and
      c1.user_id = in1.user_id and
      c1.user_id = u.user_id and
      in1.loc_id = lr.neighbor_id
  ";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  
  return array('success' => '1',
               'response' => '');
}

// getcourses function
function getcourses($session_id) {
  init_func();
  $courses = array();

  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'courses' => $courses);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'courses' => $courses);
  
  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2,
                 'courses' => $courses);
    
  $query = "select course from courses where user_id = '$user_id' order by course";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'courses' => $courses);
  
  while ($row = mysql_fetch_object($res))
    array_push($courses, $row->course);

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'courses' => $courses);

  return array('success' => '1',
               'response' => '',
               'courses' => $courses);
}

// friend_add function
function friend_add($session_id, $friend_username) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_username($friend_username)) // validate friend_username
    return array('success' => '0',
                 'response' => $GLOBALS['err_username'],
                 'session_id' => '');

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);

  $query = "select user_id from users where username = '$friend_username'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  if (!mysql_num_rows($res)) // could not find user
    return array('success' => '0',
                 'response' => 'Could not find specified friend in the system.');
  $row = mysql_fetch_object($res);
  $friend_id = $row->user_id;

  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);
  
  $query = "insert into friends (user_id, friend_id) values ('$user_id', '$friend_id')";
  $res = mysql_query($query);
  if (!$res) {
    if (mysql_errno() == 1062)
      return array('success' => '0',
                   'response' => 'The friend already exists.');
    return array('success' => '0',
                 'response' => db_err($query));
  }

  // compute new friends of friends
  $query = "
select u.session_id, u.username, in1.loc_id
from users u, friends f, in_loc in1
where in1.loc_id = '$loc_id' and
      f.user_id = '$friend_id' and
      f.friend_id = in1.user_id and
      f.friend_id = u.user_id

union all
select u.session_id, u.username, in1.loc_id
from users u, friends f, in_loc in1, loc_rel lr
where lr.loc_id = '$loc_id' and
      f.user_id = '$friend_id' and
      f.friend_id = in1.user_id and
      f.friend_id = u.user_id and
      in1.loc_id = lr.neighbor_id
  ";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  while ($row = mysql_fetch_assoc($res)) {
    // add to user's rel_queue
    $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('$session_id', '{$row["username"]}', '{$row["loc_id"]}', 'rel_add', 'fof', '$friend_username', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query));
    
    // add to target's rel_queue
    $query2 = "insert into rel_queue (session_id, username, loc_id, msg_type, rel_type, rel_param, ts) values ('{$row["session_id"]}', '$username', '$loc_id', 'rel_add', 'fof', '$friend_username', NOW())";
    $res2 = mysql_query($query2);
    if (!$res2)
      return array('success' => '0',
                   'response' => db_err($query));
  }
  
  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  return array('success' => '1',
               'response' => '');
}

// friend_del function
function friend_del($session_id, $friend_username) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_username($friend_username)) // validate friend_username
    return array('success' => '0',
                 'response' => $GLOBALS['err_username'],
                 'session_id' => '');

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);
  
  $query = "select user_id from users where username = '$friend_username'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  if (!mysql_num_rows($res)) // could not find user
    return array('success' => '0',
                 'response' => 'Could not find specified friend in the system.');

  $row = mysql_fetch_object($res);
  $friend_id = $row->user_id;
    
  $query = "delete from friends where user_id = '$user_id' and friend_id = '$friend_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  // no need to update queues here with rel_del messages, handled by client
  
  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  return array('success' => '1',
               'response' => '');
}

// getfriends function
function getfriends($session_id) {
  init_func();
  $friends = array();

  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'friends' => $friends);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'friends' => $friends);
  
  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2,
                 'friends' => $friends);
    
  $query = "select username from users, friends where users.user_id = friends.friend_id and friends.user_id = '$user_id' order by username";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'friends' => $friends);
  
  while ($row = mysql_fetch_object($res))
    array_push($friends, $row->username);

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'friends' => $friends);

  return array('success' => '1',
               'response' => '',
               'friends' => $friends);
}

// refresh function
function refresh($session_id) {
  init_func();
  $loc_q = array();
  $rel_q = array();
  $msg_q = array();

  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);

  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  
  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2,
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);

  // first retrieve location-related messages
  $query = "select msg_type as msgtype, name, loc_id, lat, loc_queue.long, distance, direction, wall from loc_queue where session_id = '$session_id' order by ts";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  $query2 = "delete from loc_queue where session_id = '$session_id'";
  $res2 = mysql_query($query2);
  if (!$res2)
    return array('success' => '0',
                 'response' => db_err($query2),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  while ($row = mysql_fetch_assoc($res))
    array_push($loc_q, $row);
  
  // second retrieve relationship-related messages
  $query = "select msg_type as msgtype, username as name, loc_id, rel_type as reltype, rel_param as relparam from rel_queue where session_id = '$session_id' order by ts";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  // this should really be in a transaction with the above query
  $query2 = "delete from rel_queue where session_id = '$session_id'";
  $res2 = mysql_query($query2);
  if (!$res2)
    return array('success' => '0',
                 'response' => db_err($query2),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  while ($row = mysql_fetch_assoc($res))
    array_push($rel_q, $row);

  // third retrieve user to user messages
  $query = "select username, msg, ts from msg_queue where session_id = '$session_id' order by ts";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  // this should really be in a transaction with the above query
  $query2 = "delete from msg_queue where session_id = '$session_id'";
  $res2 = mysql_query($query2);
  if (!$res2)
    return array('success' => '0',
                 'response' => db_err($query2),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
  while ($row = mysql_fetch_assoc($res))
    array_push($msg_q, $row);

  $query = "delete from msg_queue where session_id = '$session_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);

  return array('success' => '1',
               'response' => '',
                 'loc_q' => $loc_q,
                 'rel_q' => $rel_q,
                 'msg_q' => $msg_q);
}

// sendmsg function
function sendmsg($session_id, $username, $msg) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_username($username)) // validate username
    return array('success' => '0',
                 'response' => $GLOBALS['err_username'],
                 'session_id' => '');
  if (!valid_generic($msg)) // validate msg
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $from_username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);

  $query = "select session_id from users where username = '$username'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  if (!mysql_num_rows($res)) // could not find user
    return array('success' => '0',
                 'response' => 'Unknown user.');
  $row = mysql_fetch_row($res); // user is not online
  $to_session_id= $row[0];
  if ($to_session_id == "")
    return array('success' => '1',
                 'response' => 'User is not online.');
                   
  $query = "insert into msg_queue (session_id, username, msg, ts) values ('$to_session_id', '$from_username', '$msg', NOW())";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  
  return array('success' => '1',
               'response' => '');
}

// setwall function
function setwall($session_id, $msg) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_generic($msg)) // validate msg
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1) {
    $user_id = $p2;
    $username = $p3;
  } else
    return array('success' => '0',
                 'response' => $p2);
  
  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);

  $query = "replace into walls (loc_id, message, lastupdated_user_id, lastupdated_ts) values ('$loc_id', '$msg', '$user_id', NOW())";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  $query = "insert into loc_queue (session_id, name, loc_id, msg_type, lat, loc_queue.long, distance, direction, wall, ts) 
            select session_id, '', '$loc_id', 'wall', '', '', '', '', '$msg', NOW()
            from users, in_loc
            where users.user_id = in_loc.user_id and
            in_loc.loc_id = '$loc_id' and 
            users.user_id <> '$user_id'
  ";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  
  return array('success' => '1',
               'response' => '');
}

// getuserinfo function
function getuserinfo($session_id, $username) {
  init_func();
  $msg = "";
  $ts = "";
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.',
                 'msg' => $msg,
                 'ts' => $ts);
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.',
                 'msg' => $msg,
                 'ts' => $ts);
  if (!valid_username($username)) // validate username
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic'],
                 'msg' => $msg,
                 'ts' => $ts);

  // get user_id from username
  $query = "select user_id from users where username = '$username'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'msg' => $msg,
                 'ts' => $ts);
  if (!mysql_num_rows($res)) // invalid username
    return array('success' => '0',
                 'response' => "Unknown username.",
                 'msg' => $msg,
                 'ts' => $ts);
  $row = mysql_fetch_assoc($res);
  $user_id = $row["username"];
  
  $query = "select message, lastupdated_ts from userinfo where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'msg' => $msg,
                 'ts' => $ts);
  
  $response = "No userinfo found.";
  if (mysql_num_rows($res)) {
    $row = mysql_fetch_assoc($res);
    $msg = $row["message"];
    $ts = $row["lastupdated_ts"];
    $response = "";
  }

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query),
                 'msg' => $msg,
                 'ts' => $ts);
  
  return array('success' => '1',
               'response' => $response,
               'msg' => $msg,
               'ts' => $ts);
}

// setuserinfo function
function setuserinfo($session_id, $msg) {
  init_func();
  if (!db_connect()) // connect to the database
    return array('success' => '0',
                 'response' => 'Unable to connect to database.');
  
  if (!valid_session_id($session_id)) // validate session_id
    return array('success' => '0',
                 'response' => 'Invalid session.');
  if (!valid_generic($msg)) // validate msg
    return array('success' => '0',
                 'response' => $GLOBALS['err_generic']);

  list($p1, $p2, $p3) = getuser($session_id);
  if ($p1)
    $user_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);
  
  list($p1, $p2) = getloc($user_id);
  if ($p1)
    $loc_id = $p2;
  else
    return array('success' => '0',
                 'response' => $p2);

  $query = "replace into userinfo (user_id, message, lastupdated_ts) values ('$loc_id', '$msg', NOW())";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));

  $query = "update users set lastreq_ts = NOW() where user_id = '$user_id'";
  $res = mysql_query($query);
  if (!$res)
    return array('success' => '0',
                 'response' => db_err($query));
  
  return array('success' => '1',
               'response' => '');
}

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?>